rem
	====================================================================
	
	BlitzOgre3D
	
	Blitz3D-like Interface to the Ogre3D Engine
	
	====================================================================
endrem
Const RSS_DIRECT3D9:Int		= 1
Const RSS_OPENGL:Int		= 2
Const RSS_DIRECT3D9_D:Int	= 3
Const RSS_OPENGL_D:Int		= 4

Type B3DEntity
	Global _list:TList
	Field _typ:Int
	Field obj:Object
	Field _rigidbody:TRigidBody
	
	Method New()
		If Self._list = Null Then Self._list = New TList
		self._list.AddLast(self)
	End Method
End Type


Type TBlitz3D
	Global _root:Root
	Global _rendersystem:RenderSystem
	Global _renderwindow:RenderWindow
	Global _logmanager:LogManager
	Global _scenemanager:SceneManager
	Global _resGroupManager:ResourceGroupManager
	Global _viewport:Viewport
	Global _rootscenenode:SceneNode
	
	Field _renderer:Int
	Field _plugin_cfg:String
	Field _config_file:String
	Field _logfile:String
	Field _apptitle:String
	Global _resloc:TList	
	Field _gfx:TGraphics
	Field _physics:TBullet
	Field cmp:CompositorManager
	
	Field entities:TMap
	Global instance:Byte
	
	Method New()
		If Not TBlitz3D.instance
			Self._plugin_cfg	= "plugins.cfg"
			Self._config_file	= "ogre.cfg"
			Self._logfile		= "ogre.log"
			
			?Win32
			Self._renderer		= RSS_DIRECT3D9
			?Linux
			Self._renderer		= RSS_OPENGL
			?MacOs
			Self._renderer		= RSS_OPENGL
			?
			
			Self._apptitle		= "BlitzOgre3D"
			Self._resloc		= New TList
			Self.instance		= True
			Self.entities		= CreateMap()
			Self.cmp			= New CompositorManager
		EndIf
	End Method
	
	
	Method Init(plugins:String = "plugins.cfg", config:String = "ogre.cfg", logfile:String = "ogre.log")
		Self._plugin_cfg	= plugins
		Self._config_file	= config
		Self._logfile		= logfile
		
		Self._root			= Root.Create(Self._plugin_cfg, Self._config_file, Self._logfile)
	End Method
	
	
	Function addResLoc(location:String, locType:String = "FileSystem")
		Local found:Byte = False
		For Local r:String = EachIn TBlitz3D._resloc
			If(r = location) 
				found = True
				Exit
			EndIf
		Next
		
		If found = False
			If ExtractExt(location) = "zip" Then locType = "Zip"
			TBlitz3D._resGroupManager.addResourceLocation(location, locType, "BlitzOgre3D")
			TBlitz3D._resGroupManager.initialiseResourceGroup("BlitzOgre3D")
			TBlitz3D._resloc.AddLast(location)
		EndIf
	End Function
	
	Method setRenderer(renderer:Int = RSS_DIRECT3D9)
		Self._renderer = renderer
	End Method
	
	
	Method AppTitle(title:String)
		Self._apptitle = title;
	End Method
	
	
	Method Graphics3D(width:Int, Height:Int, depth:Int = 0, hertz:Int = 60, flags:Int = 0)
		If Self._root = Null Then Self._root = Root.Create(Self._plugin_cfg, Self._config_file, Self._logfile)

		Local rsname:String = ""
		Local fullscreen:Byte = False
		If depth > 0 Then fullscreen = True
		
		Select Self._renderer
			Case RSS_DIRECT3D9	; rsname = "Direct3D9 Rendering Subsystem"
			Case RSS_OPENGL		; rsname = "OpenGL Rendering Subsystem"
		End Select
		
		Self._gfx = Graphics(width, Height, depth, hertz, flags)
		Local hWnd:Int = GetForegroundWindow()
		Local tags:String = ""
		tags:+ "externalWindowHandle|" + String(hWnd) + "|"
		tags:+ "left|" + String(0) + "|"
		tags:+ "top|" + String(0) + "|"
		
		Self._rendersystem		= Self._root.getRenderSystemByName(rsname)
		Self._root.setRenderSystem(Self._rendersystem)
		Self._root.initialise(False, Self._apptitle)
		Self._renderwindow		= Self._root.createRenderWindow(Self._apptitle, width, Height, fullscreen, tags)
		Self._logmanager		= New LogManager
		Self._scenemanager		= Self._root.createSceneManager()
		Self._rootscenenode		= Self._scenemanager.getRootSceneNode()
		Self._resGroupManager	= New ResourceGroupManager
		Self._resGroupManager.createResourceGroup("BlitzOgre3D")
				
		OnEnd shutDownOgre
	End Method	
	
	
	Method Graphics3DExt(width:Int, Height:Int, depth:Int = 0, hertz:Int = 60, hWnd:Int = 0, renderer:Int = RSS_DIRECT3D9)
		If Self._root = Null Then Self._root = Root.Create(Self._plugin_cfg, Self._config_file, Self._logfile)

		Local rsname:String = ""
		Local fullscreen:Byte = False
		If depth > 0 Then fullscreen = True
		
		Select renderer
			Case RSS_DIRECT3D9	; rsname = "Direct3D9 Rendering Subsystem"
			Case RSS_OPENGL		; rsname = "OpenGL Rendering Subsystem"
			Default				; rsname = "Direct3D9 Rendering Subsystem"
		End Select
		
		'Self._gfx = Graphics(width, Height, depth, hertz, flags)
		'Local hWnd:Int = GetForegroundWindow()
		Local tags:String = ""
		tags:+ "externalWindowHandle|" + String(hWnd) + "|"
		tags:+ "left|" + String(0) + "|"
		tags:+ "top|" + String(0) + "|"
		
		Self._rendersystem		= Self._root.getRenderSystemByName(rsname)
		Self._root.setRenderSystem(Self._rendersystem)
		Self._root.initialise(False, Self._apptitle)
		Self._renderwindow		= Self._root.createRenderWindow(Self._apptitle, width, Height, fullscreen, tags)
		Self._logmanager		= New LogManager
		Self._scenemanager		= Self._root.createSceneManager()
		Self._rootscenenode		= Self._scenemanager.getRootSceneNode()
		Self._resGroupManager	= New ResourceGroupManager
		Self._resGroupManager.createResourceGroup("BlitzOgre3D")
				
		OnEnd shutDownOgre
	End Method	
	
	
	Method EndGraphics()
		Self._root.Shutdown()
	End Method
	
	
	Method RenderWorld()
		Self._root.renderOneFrame()
	End Method
	
	
	Method startPhysics(gravX:Float = 0.0, gravY:Float = -9.81, gravZ:Float = 0.0)
		If Self._physics = Null Then  Self._physics = TBullet.Init(gravX, gravY, gravZ)
	End Method
	
	
	Method endPhysics()
		Self._physics.Shutdown()
	End Method
	
	
	Method _AddEntity(entity_name:String, ent:B3DEntity)
		Self.entities.Insert(entity_name, ent)
	End Method
	
	
	Method _findEntity:B3DEntity(entity_name:String)
		Return B3DEntity(Self.entities.ValueForKey(entity_name))
	End Method
End Type
Global _blitzogre3d:TBlitz3D = New TBlitz3D


Function SetRenderer(renderer:Int = RSS_DIRECT3D9)
	getBlitz3D().setRenderer(renderer)
End Function


Function Init(plugins:String = "plugins.cfg", config:String = "ogre.cfg", logfile:String = "ogre.log")
	getBlitz3D().Init(plugins, config, logfile)
End Function


Function Graphics3D(width:Int, Height:Int, depth:Int = 0, hertz:Int = 60, flags:Int = 0)
	getBlitz3D().Graphics3D(width, Height, depth, hertz, flags)
End Function

Function Graphics3DExt(width:Int, Height:Int, depth:Int = 0, hertz:Int = 60, hWnd:Int = 0, renderer:Int = RSS_DIRECT3D9)
	getBlitz3D().Graphics3DExt(width, Height, depth, hertz, hWnd, renderer)
End Function

Function RenderWorld()
	getBlitz3D().RenderWorld()
End Function

Function UpdateWorld()
	If B3DEntity._list <> Null
		Local _pos:bVector3
		Local _rot:bQuaternion
		
		For Local be:B3DEntity = EachIn B3DEntity._list
			If Entity(be.obj) Or Mesh(be.obj)
				If be._rigidbody <> Null
					_pos = getPhysicsHandle().RigidBodyPosition(be._rigidbody)
					_rot = getPhysicsHandle().RigidBodyRotation(be._rigidbody)
						
					Entity(be.obj).SetPosition(_pos.GetX(), _pos.GetY(), _pos.GetZ())
					Entity(be.obj).SetOrientation(_rot)	
				End If
			EndIf
		Next
	End If
	
	getBlitz3D()._physics.Update()
End Function

Function shutDownOgre()
	getBlitz3D().endPhysics()
	getBlitz3D().EndGraphics()
End Function


Function AmbientLight(r:Float, g:Float, b:Float)
	getSceneManager().setAmbientLight(ColourValue.Create(r, g, b, 1.0))
End Function


Function SetShadowTechnique(technique:Int = SHADOWTYPE_STENCIL_MODULATIVE)
	getSceneManager().SetShadowTechnique(technique)
	getSceneManager().setShadowUseLightClipPlanes(False)
End Function


Function setShadowFarDistance(distance:Float = 100.0)
	getSceneManager().setShadowFarDistance(distance)
End Function


Function SetShadowTextureSize(texsize:Int = 512)
	getSceneManager().SetShadowTextureSize(texsize)
End Function


Function getSceneManager:SceneManager()
	Return getBlitz3D()._scenemanager
End Function


Function getPhysicsHandle:TBullet()
	Return getBlitz3D()._physics
End Function


Function LoadSkyBox(materialFile:String, distance:Float = 5000.0)
	getBlitz3D().addResLoc(ExtractDir(materialFile))
	Local sbMat:String = StripAll(materialFile)
	
	getSceneManager().setSkyBox(True, sbMat, distance)
End Function


Function getBlitz3D:TBlitz3D()
	Return _blitzogre3d
End Function


Function Physics(gravX:Float = 0.0, gravY:Float = -9.81, gravZ:Float = 0.0)
	getBlitz3D().startPhysics(gravX, gravY, gravZ)
End Function
